namespace Standards.Data.EntityFramework.Migrations
{
    using System.Data.Entity.Migrations;
    using System.Linq;
    using System.Collections.Generic;
    using Standards.Model.Models;
    using Standards.Services.Services;
    using System.Data.Entity;

    public sealed class StandardsMigrationConfiguration : DbMigrationsConfiguration<StandardsContext>
    {
        public StandardsMigrationConfiguration()
        {
            this.AutomaticMigrationsEnabled = false;
        }

        protected override void Seed(StandardsContext context)
        {
            //  This method will be called after migrating to the latest version.

            // Add the permissions
            var permissions = this.GetPermissions();
            context.Permissions.AddOrUpdate(p => p.Id, permissions.ToArray());

            // Add the built-in roles
            var builtInRoles = this.GetBuiltInRoles(context);
            context.Roles.AddOrUpdate(r => r.Name, builtInRoles.ToArray());
            
            // Add an admin user if one doesn't exist
            // Currently, the user must edit the database manually to set the admin user name
            // In future this would be done as part of the installation routine
            var adminPresent = context.Users.Any(u => u.IsAdmin);
            if (adminPresent)
            {
                return;
            }

            context.Users.Add(
                new UserDto
                    {
                        Name = @"E.g. MyDomain\MyUser",
                        IsActive = true,
                        IsAdmin = true
                    });
        }

        private IEnumerable<PermissionDto> GetPermissions()
        {
            //TODO: dependency injection
            var permissionsService = new PermissionsService(new StandardsUnitOfWorkFactory());
            var permissions = permissionsService.GetAvailablePermissions();
            return permissions.Select(GetPermissionDto);
        }

        private IEnumerable<RoleDto> GetBuiltInRoles(StandardsContext context)
        {
            var builtInRoles = new List<RoleDto>
                {
                    new RoleDto
                    {
                        Name = "Viewer", 
                        Permissions = new List<PermissionDto> 
                        {
                            context.Permissions.FindPermission(Permission.CanViewStandards)
                        }
                    },
                    new RoleDto
                    {
                        Name = "Editor",
                        Permissions = new List<PermissionDto>
                        {
                            context.Permissions.FindPermission(Permission.CanViewStandards)
                        }
                    },
                    new RoleDto
                    {
                        Name = "Approver",
                        Permissions = new List<PermissionDto>
                        {
                            context.Permissions.FindPermission(Permission.CanViewStandards)
                        }
                    }
                };

            return builtInRoles;
        }

        private static PermissionDto GetPermissionDto(Permission permission)
        {
            return new PermissionDto { Id = (int)permission, Permission = permission };
        }
    }

    internal static class PermissionDtoExtensions
    {
        internal static PermissionDto FindPermission(this DbSet<PermissionDto> dbSet, Permission permission)
        {
            return dbSet.Find((int)permission);
        }
    }
}